﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

using System.IO;
using System.Drawing;
using System.Windows.Forms;

using Xceed.Wpf.Toolkit;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;

namespace MedVis
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        double gridWidth = 0;
        double gridHeight = 0;

        string[] imgArray;
        MyImageObject currentImage;
        ObservableCollection<String> img = new ObservableCollection<String>();
        public ImageStack iS;

        OpenFileDialog openFileDialog;
        SaveFileDialog saveFileDialog;
        FolderBrowserDialog folderDialog;
        BackgroundWorker worker;

        System.Windows.Point cursorPosOld;
        System.Windows.Point cursorPosNew;

        System.Windows.Vector ImageSize = new System.Windows.Vector(0,0);
        static double scalefactorX = 1;
        static double scalefactorY = 1;
        static double dpiX, dpiY, imgWidth, imgHeight = 0;

        bool unsaved = false;

        public MainWindow()
        {
            InitializeComponent();

            iS = ImageStack.GetInstance;
            this.DataContext = this;
            initDialogs();
            Properties.Settings.Default.currentFilePath = "";

            slider_Prev.Value = Properties.Settings.Default.opacityPrev;
            slider_Current.Value = Properties.Settings.Default.opacityCurr;
            slider_Next.Value = Properties.Settings.Default.opacityNext;
        }

        private void displayImage(string path)
        {
            int index = list.SelectedIndex;
            //load previouse image
            if(index-1 >= 0)
                imageDisplayPrev.Source = new BitmapImage(new Uri(iS.getImage(index - 1).path));
            else
                imageDisplayPrev.Source = new BitmapImage(new Uri(iS.getImage(list.Items.Count-1).path));

            //load current image
            BitmapImage bmpi = new BitmapImage(new Uri(path));
            imageDisplay.Source = bmpi;
            WriteableBitmap wbmp = new WriteableBitmap(bmpi);
            dpiX = wbmp.DpiX;
            dpiY = wbmp.DpiY;
            imgWidth = wbmp.PixelWidth;
            imgHeight = wbmp.PixelHeight;
            ImageSize = imageDisplay.PointToScreen(new System.Windows.Point(imageDisplay.ActualWidth, imageDisplay.ActualHeight)) - imageDisplay.PointToScreen(new System.Windows.Point(0, 0));
            scalefactorX = wbmp.PixelWidth / ImageSize.X;
            scalefactorY = wbmp.PixelHeight / ImageSize.Y;

            //load next image
            if (index < list.Items.Count-1)
                imageDisplayNext.Source = new BitmapImage(new Uri(iS.getImage(list.SelectedIndex + 1).path));
            else
                imageDisplayNext.Source = new BitmapImage(new Uri(iS.getImage(0).path));
        }
        private void loadImgValues()
        {
            tb_rota.Value = currentImage.rota;
            tb_offsetX.Value = currentImage.offsetX;
            tb_offsetY.Value = currentImage.offsetY;

            int index = list.SelectedIndex;
            //load previouse image
            if (index - 1 >= 0)
            {
                rotateTransformPrev.Angle = iS.getImage(index - 1).rota;
                translateTransformPrev.X = iS.getImage(index - 1).offsetX;
                translateTransformPrev.Y = iS.getImage(index - 1).offsetY;
                imageDisplayPrev.Source = new BitmapImage(new Uri(iS.getImage(index - 1).path));
            }
            else
            {
                rotateTransformPrev.Angle = iS.getImage(list.Items.Count - 1).rota;
                translateTransformPrev.X = iS.getImage(list.Items.Count - 1).offsetX;
                translateTransformPrev.Y = iS.getImage(list.Items.Count - 1).offsetY;
            }

            if (index < list.Items.Count - 1)
            {
                rotateTransformNext.Angle = iS.getImage(list.SelectedIndex + 1).rota;
                translateTransformNext.X = iS.getImage(list.SelectedIndex + 1).offsetX;
                translateTransformNext.Y = iS.getImage(list.SelectedIndex + 1).offsetY;
            }
            else
            {
                rotateTransformNext.Angle = iS.getImage(0).rota;
                translateTransformNext.X = iS.getImage(0).offsetX;
                translateTransformNext.Y = iS.getImage(0).offsetY;
            }
        }
        private void saveImgValues()
        {
            if (iS.imageObjects.Count >= 1)
            {
                currentImage = iS.getImage(list.SelectedIndex);
                currentImage.rota = tb_rota.Value.Value;
                currentImage.offsetX = tb_offsetX.Value.Value;
                currentImage.offsetY = tb_offsetY.Value.Value;
            }
        }
        private void loadIsValues()
        {
            
            tb_cropTop.Value = iS.cropTop;
            tb_cropLeft.Value = iS.cropLeft;
            tb_cropBot.Value = iS.cropBot;
            tb_cropRight.Value = iS.cropRight;
            tb_heightMm.Value = iS.stackHeight;
            tb_widthMm.Value = iS.stackWidth;
            tb_sliceMm.Value = iS.sliceThickness;
            slider_Prev.Value = iS.opacityPrev;
            slider_Current.Value = iS.opacityCurr;
            slider_Next.Value = iS.opacityNext;
        }
        private void saveIsValues()
        {
            if (iS.imageObjects.Count >= 1)
            { 
            iS.cropTop = Convert.ToInt32(tb_cropTop.Value);
            iS.cropLeft = Convert.ToInt32(tb_cropLeft.Value);
            iS.cropBot = Convert.ToInt32(tb_cropBot.Value);
            iS.cropRight = Convert.ToInt32(tb_cropRight.Value);
            iS.sliceThickness = tb_sliceMm.Value.Value;
            iS.stackHeight = tb_heightMm.Value.Value;
            iS.stackWidth = tb_widthMm.Value.Value;
            iS.opacityPrev = slider_Prev.Value;
            iS.opacityCurr = slider_Current.Value;
            iS.opacityNext = slider_Next.Value;
            }
        }

        private void nextImg()
        {
            try
            {
                //alte werte eintragen
                saveImgValues();
                //bild wechseln und neue werte anzeigen
                currentImage = iS.getNextImage();
                loadImgValues();

                if (list.SelectedIndex < imgArray.Length - 1)
                    list.SelectedIndex += 1;
                else
                    list.SelectedIndex = 0;
                list.ScrollIntoView(list.SelectedItem);
            }
            catch (Exception exc)
            {
                Console.WriteLine("keine bilder geladen!");
            }
        }
        private void prevImg()
        {
            try
            {
                //alte werte eintragen
                saveImgValues();

                //bild wechseln und neue werte anzeigen
                currentImage = iS.getPreviusImage();
                loadImgValues();
                //displayImage(currentImage.path);

                if (list.SelectedIndex > 0)
                    list.SelectedIndex -= 1;
                else
                    list.SelectedIndex = imgArray.Length - 1;
                list.ScrollIntoView(list.SelectedItem);
            }
            catch (Exception exc)
            {
                Console.WriteLine("keine bilder geladen!");
            }
        }

        private void Exit(object sender, RoutedEventArgs e)
        {
            Close();
        }

        //image laden, neues projekt
        private void newProject(object sender, EventArgs e)
        {
            openFolder();
        }

        private void Next_Image_Click(object sender, RoutedEventArgs e)
        {
            nextImg();
        }

        private void Prev_Image_Click(object sender, RoutedEventArgs e)
        {
            prevImg();
        }

        private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                //alte werte eintragen
                currentImage.rota = tb_rota.Value.Value;
                currentImage.offsetX = tb_offsetX.Value.Value;
                currentImage.offsetY = tb_offsetY.Value.Value;
                //bild wechseln und neue werte anzeigen
                currentImage = iS.getImage(list.SelectedIndex);
                loadImgValues();
                displayImage(currentImage.path);
            }
            catch (Exception exc)
            {
                Console.WriteLine("keine bilder geladen!");
            }
        }


        private void load(object sender, RoutedEventArgs e)
        {
            openFile();
        }

        private void saveAs(object sender, RoutedEventArgs e)
        {
            //saveIsValues();
            if (iS.imageObjects.Count >= 1)
            {
                saveFile();
            }
        }
        
        private void export(object sender, RoutedEventArgs e)
        {
            if (iS.imageObjects.Count >= 1)
            {
                exportFile();
            }
        }

        private void window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.E && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
            {
                export(sender, e);
            }

            if (e.Key == Key.A)
            {
                tb_offsetX.Value -= 1;
                unsaved = true;
            }
            if (e.Key == Key.D)
            {
                tb_offsetX.Value += 1;
                unsaved = true;
            }
            if (e.Key == Key.W)
            {
                tb_offsetY.Value -= 1;
                unsaved = true;
            }
            if (e.Key == Key.S)
            {
                tb_offsetY.Value += 1;
                unsaved = true;
            }
            if (e.Key == Key.E && (Keyboard.Modifiers & ModifierKeys.None) == ModifierKeys.None)
            {
                tb_rota.Value += 0.1;
                unsaved = true;
            }
            if (e.Key == Key.Q)
            {
                tb_rota.Value -= 0.1;
                unsaved = true;
            }
            if (e.Key == Key.PageDown || e.Key == Key.Subtract)
            {
                moveImgDown(sender, e);
            }
            if (e.Key == Key.PageUp || e.Key == Key.Add)
            {
                moveImgUp(sender, e);
            }
            if (e.Key == Key.Escape || e.Key == Key.Enter)
            {
                Next_Image.Focus();
            }
        }

        private void window_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (e.Delta < 0)
            {
                nextImg();
            }
            if (e.Delta > 0)
            {
                prevImg();
            }
        }

        private void resetImgButton_Click(object sender, RoutedEventArgs e)
        {
            tb_offsetX.Value = 0;
            tb_offsetY.Value = 0;
            tb_rota.Value = 0;
            unsaved = true;
        }

        private void cb_prevImg_Checked(object sender, RoutedEventArgs e)
        {
            vb_prev.Visibility = Visibility.Visible;
        }

        private void cb_prevImg_Unchecked(object sender, RoutedEventArgs e)
        {
            vb_prev.Visibility = Visibility.Hidden;
        }

        private void cb_nextImg_Checked(object sender, RoutedEventArgs e)
        {
            vb_next.Visibility = Visibility.Visible;
        }

        private void cb_nextImg_Unchecked(object sender, RoutedEventArgs e)
        {
            vb_next.Visibility = Visibility.Hidden;
        }

        private void vb_current_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (e.RightButton == MouseButtonState.Pressed )
            {
                cursorPosNew = Mouse.GetPosition(System.Windows.Application.Current.MainWindow);
                if (cursorPosOld.X < cursorPosNew.X && cursorPosOld.Y < cursorPosNew.Y)
                {
                    markRect.Margin = new Thickness(cursorPosOld.X, cursorPosOld.Y, 0, 0);
                    markRect.Width = cursorPosNew.X - cursorPosOld.X;
                    markRect.Height = cursorPosNew.Y - cursorPosOld.Y;
                }
                if (cursorPosOld.X > cursorPosNew.X && cursorPosOld.Y > cursorPosNew.Y)
                {
                    markRect.Margin = new Thickness(cursorPosNew.X, cursorPosNew.Y, 0, 0);
                    markRect.Width = cursorPosOld.X - cursorPosNew.X;
                    markRect.Height = cursorPosOld.Y - cursorPosNew.Y;
                }
                if (cursorPosOld.X > cursorPosNew.X && cursorPosOld.Y < cursorPosNew.Y)
                {
                    markRect.Margin = new Thickness(cursorPosNew.X, cursorPosOld.Y, 0, 0);
                    markRect.Width = cursorPosOld.X - cursorPosNew.X;
                    markRect.Height = cursorPosNew.Y - cursorPosOld.Y;
                }
                if (cursorPosOld.X < cursorPosNew.X && cursorPosOld.Y > cursorPosNew.Y)
                {
                    markRect.Margin = new Thickness(cursorPosOld.X, cursorPosNew.Y, 0, 0);
                    markRect.Width = cursorPosNew.X - cursorPosOld.X;
                    markRect.Height = cursorPosOld.Y - cursorPosNew.Y;
                }
            }
            if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.Modifiers & ModifierKeys.None) == ModifierKeys.None)
            {
                cursorPosNew = Mouse.GetPosition(System.Windows.Application.Current.MainWindow);
                if (cursorPosOld.Y < cursorPosNew.Y)
                    nextImg();
                if (cursorPosOld.Y > cursorPosNew.Y)
                    prevImg();
                cursorPosOld = cursorPosNew;
            }

            if (e.MiddleButton == MouseButtonState.Pressed && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
            {
                cursorPosNew = Mouse.GetPosition(System.Windows.Application.Current.MainWindow);
                if (cursorPosOld.Y < cursorPosNew.Y)
                    tb_rota.Value += 1;
                if (cursorPosOld.Y > cursorPosNew.Y)
                    tb_rota.Value -= 1;
                cursorPosOld = cursorPosNew;
            }
            if (e.MiddleButton == MouseButtonState.Pressed && (Keyboard.Modifiers & ModifierKeys.None) == ModifierKeys.None)
            {
                cursorPosNew = Mouse.GetPosition(System.Windows.Application.Current.MainWindow);
                if (cursorPosOld.X < cursorPosNew.X)
                    tb_offsetX.Value += 1;
                if (cursorPosOld.X > cursorPosNew.X)
                    tb_offsetX.Value -= 1;
                if (cursorPosOld.Y < cursorPosNew.Y)
                    tb_offsetY.Value += 1;
                if (cursorPosOld.Y > cursorPosNew.Y)
                    tb_offsetY.Value -= 1;
                cursorPosOld = cursorPosNew;
            }
        }

        private void window_SizeChanged(object sender, SizeChangedEventArgs e)
        {

            System.Windows.Vector v = imageDisplay.PointToScreen(new System.Windows.Point(imageDisplay.ActualWidth, imageDisplay.ActualHeight)) - imageDisplay.PointToScreen(new System.Windows.Point(0, 0));
            scalefactorX = v.X / ImageSize.X;
            scalefactorY = v.Y / ImageSize.Y;
            if (double.IsNaN(scalefactorX) || double.IsInfinity(scalefactorX))
                scalefactorX = 1;
            if (double.IsNaN(scalefactorY) || double.IsInfinity(scalefactorY))
                scalefactorY = 1;

            wp_cropBot.Height *= scalefactorY;
            wp_cropLeft.Width *= scalefactorX;
            wp_cropRight.Width *= scalefactorX;
            wp_cropTop.Height *= scalefactorY;

            ImageSize = imageDisplay.PointToScreen(new System.Windows.Point(imageDisplay.ActualWidth, imageDisplay.ActualHeight)) - imageDisplay.PointToScreen(new System.Windows.Point(0, 0));

            refreshCropPos();
        }

        private void window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Properties.Settings.Default.opacityPrev = slider_Prev.Value;
            Properties.Settings.Default.opacityCurr = slider_Current.Value;
            Properties.Settings.Default.opacityNext = slider_Next.Value;
            Properties.Settings.Default.Save();
            checkUnsaveB4Leave();
        }
        private void checkUnsaveB4Leave()
        {
            if (unsaved)
            {
                MessageBoxResult result = System.Windows.MessageBox.Show("There are unsaved changes, would you like to save??", "Save changes?", MessageBoxButton.YesNo, MessageBoxImage.Warning);
                if (result == MessageBoxResult.Yes)
                {
                    save(new object(), new RoutedEventArgs());
                }
            }
        }

        private void newImgAbove(object sender, RoutedEventArgs e)
        {
            if (list.SelectedIndex > 0 && list.SelectedIndex < list.Items.Count)
            {
                WriteableBitmap wbmp = createImage1(iS.getImage(list.SelectedIndex-1).path, iS.getImage(list.SelectedIndex).path);
                imageDisplay.Source = wbmp;
                string newImgPath = iS.getImage(list.SelectedIndex).path+"_generatedPrev.png";
                toPng(newImgPath, wbmp);
                iS.imageObjects.Add(new MyImageObject(newImgPath));
                iS.imageObjects.Move(iS.imageObjects.Count - 1, list.SelectedIndex);
                img.Add(newImgPath);
                img.Move(img.Count-1, list.SelectedIndex);

                refreshList();
                list.SelectedIndex -= 1;
            }
        }

        private void newImgBelow(object sender, RoutedEventArgs e)
        {
            if (list.SelectedIndex >= 0 && list.SelectedIndex < list.Items.Count-1)
            {
                WriteableBitmap wbmp = createImage1(iS.getImage(list.SelectedIndex).path, iS.getImage(list.SelectedIndex + 1).path);
                imageDisplay.Source = wbmp;
                string newImgPath = iS.getImage(list.SelectedIndex).path + "_generatedNext.png";
                toPng(newImgPath, wbmp);
                iS.imageObjects.Add(new MyImageObject(newImgPath));
                iS.imageObjects.Move(iS.imageObjects.Count - 1, list.SelectedIndex+1);
                img.Add(newImgPath);
                img.Move(img.Count - 1, list.SelectedIndex+1);

                refreshList();
                list.SelectedIndex += 1;
            }
        }
        private void moveImgUp(object sender, RoutedEventArgs e)
        {
            if (list.SelectedIndex > 0 && list.SelectedIndex < list.Items.Count)
            {
                iS.imageObjects.Move(list.SelectedIndex, list.SelectedIndex - 1);
                img.Move(list.SelectedIndex, list.SelectedIndex - 1);
                refreshList();
            }
        }
        private void moveImgDown(object sender, RoutedEventArgs e)
        {
            if (list.SelectedIndex >= 0 && list.SelectedIndex < list.Items.Count - 1)
            {
                iS.imageObjects.Move(list.SelectedIndex, list.SelectedIndex + 1);
                img.Move(list.SelectedIndex, list.SelectedIndex + 1);
                refreshList();
            }
        }
        private void removeImg(object sender, RoutedEventArgs e)
        {
            iS.getAllImages().RemoveAt(list.SelectedIndex);
            img.RemoveAt(list.SelectedIndex);

            int lastSelect = list.SelectedIndex;
            refreshList();
            list.SelectedIndex = lastSelect;
        }

        private void refreshList()
        {
            //nur bildnamen in liste, ohne pfad
            int i = 0;
            int lastSelect = list.SelectedIndex;
            imgArray = img.ToArray();
            for (int q = 0; q < imgArray.Length; q++)
            {
                i = imgArray[q].LastIndexOf("\\") + 1;
                imgArray[q] = imgArray[q].Substring(i);
            }
            list.ItemsSource = imgArray;
            list.InvalidateVisual();
        }

        public static double[] getImageValues()
        {
            return new double[] { scalefactorX, scalefactorY, dpiX, dpiY, imgWidth, imgHeight };
        }
    }
}
